package com.test.mchelepesa.view_rice;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Looper;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.LinearLayout;

import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.appcompat.widget.AppCompatTextView;

import com.test.mchelepesa.R;

public class GradientTextView_rice extends AppCompatTextView {

    private LinearGradient linearGradient;

    @ColorInt
    private int startColor;
    @ColorInt
    private int endColor;
    @ColorInt
    private int[] colorArr = null;
    private float[] positionArr = null;

    @AttrRes
    private int orientation;

    public GradientTextView_rice(Context context) {
        super(context);
        init(context, null);
    }

    public GradientTextView_rice(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public GradientTextView_rice(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {

        if (attrs!=null){
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.GradientTextView_rice);
            startColor = typedArray.getColor(R.styleable.GradientTextView_rice_android_startColor,Color.BLACK);
            endColor = typedArray.getColor(R.styleable.GradientTextView_rice_android_endColor,Color.BLACK);
            orientation = typedArray.getInt(R.styleable.GradientTextView_rice_android_orientation, LinearLayout.HORIZONTAL);
            typedArray.recycle();
        }

        setTextColor(Color.WHITE);

    }

    public void setGradient(int[] colors, float[] positions, @AttrRes int orientation){
        if (colors==null || (positions!=null && positions.length!=colors.length)) return;
        this.colorArr = colors;
        this.positionArr = positions;
        this.orientation = orientation;

        if (Looper.myLooper()==Looper.getMainLooper()) invalidate();
        else postInvalidate();
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {

        float x0 = 0;
        float y0 = 0;
        float x1 = 0;
        float y1 = 0;

        Rect bounds = calculateTextBounds();

        if (bounds!=null){
            if (orientation == LinearLayout.VERTICAL) {
                y0 = bounds.top;
                y1 = bounds.bottom;
            }
            else {
                x0 = bounds.left;
                x1 = bounds.right;
            }
        }

        if (colorArr == null) colorArr = new int[]{startColor,endColor};

        linearGradient = new LinearGradient(x0, y0, x1, y1,
                colorArr,
                positionArr,
                Shader.TileMode.CLAMP);

        getPaint().setShader(linearGradient);

        super.onDraw(canvas);

    }

    private Rect calculateTextBounds(){
        String text = getText().toString();
        TextPaint paint = getPaint();

        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        if (availableWidth <= 0) {
            return null;
        }

        StaticLayout layout = createStaticLayout(text, paint, availableWidth);

        if (layout == null) {
            return null;
        }

        Rect bounds = new Rect();
        for (int i = 0; i < layout.getLineCount(); i++) {
            int lineTop = layout.getLineTop(i);
            int lineBottom = layout.getLineBottom(i);

            if (i == 0) {
                bounds.left = (int) layout.getLineLeft(i);
                bounds.top = lineTop;
                bounds.right = (int) layout.getLineRight(i);
                bounds.bottom = lineBottom;
            } else {
                bounds.left = Math.min(bounds.left, (int) layout.getLineLeft(i));
                bounds.right = Math.max(bounds.right, (int) layout.getLineRight(i));
                bounds.bottom = lineBottom;
            }
        }

        adjustBoundsForGravity(bounds, layout);

        return bounds;
    }

    private StaticLayout createStaticLayout(String text, TextPaint paint, int availableWidth) {
        float spacingMult = getLineSpacingMultiplier();
        float spacingAdd = getLineSpacingExtra();
        boolean includePad = true;

        StaticLayout layout;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
            layout = StaticLayout.Builder.obtain(text, 0, text.length(), paint, availableWidth)
                    .setLineSpacing(spacingAdd, spacingMult)
                    .setIncludePad(includePad)
                    .build();
        } else {
            layout = new StaticLayout(text, paint, availableWidth, Layout.Alignment.ALIGN_NORMAL,
                    spacingMult, spacingAdd, includePad);
        }

        return layout;
    }

    @SuppressLint("RtlHardcoded")
    private void adjustBoundsForGravity(Rect bounds, StaticLayout layout) {

        int gravity = getGravity();
        int width = getWidth();
        int height = getHeight();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();

        bounds.left += paddingLeft;
        bounds.top += paddingTop;
        bounds.right += paddingLeft;
        bounds.bottom += paddingTop;

        int gravityH = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
        int totalWidth = bounds.right - bounds.left;

        if (gravityH == Gravity.CENTER_HORIZONTAL) {
            int offset = (width - totalWidth) / 2 - paddingLeft;
            bounds.left += offset;
            bounds.right += offset;
        } else if (gravityH == Gravity.LEFT) {
            bounds.left = paddingLeft;
            bounds.right = bounds.left + totalWidth;
        } else if (gravityH == Gravity.RIGHT) {
            bounds.right = width - paddingRight;
            bounds.left = bounds.right - totalWidth;
        }

        int gravityV = gravity & Gravity.VERTICAL_GRAVITY_MASK;
        int totalHeight = bounds.bottom - bounds.top;

        if (gravityV == Gravity.CENTER_VERTICAL) {
            int offset = (height - totalHeight) / 2 - paddingTop;
            bounds.top += offset;
            bounds.bottom += offset;
        } else if (gravityV == Gravity.TOP) {
            bounds.top = paddingTop;
            bounds.bottom = bounds.top + totalHeight;
        }else if (gravityV == Gravity.BOTTOM) {
            bounds.bottom = height - paddingBottom;
            bounds.top = bounds.bottom - totalHeight;
        }

    }

}
